package com.freecloud.bitorrent.config;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextClosedEvent;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @Author: maomao
 * @Date: 2022/7/15 5:59 PM
 */
@Configuration
@ConfigurationProperties(prefix = "netty")
public class NettyConfig implements ApplicationListener<ContextClosedEvent> {
    private final ChannelInitializer channelInitializer;
    @Value("${netty.udp.port}")
    private int udpPort;
    @Value("${netty.so.rcvbuf}")
    private int rcvbuf;
    @Value("${netty.so.sndbuf}")
    private int sndbuf;

    private EventLoopGroup group;

    public NettyConfig(ChannelInitializer channelInitializer) {
        this.channelInitializer = channelInitializer;
    }

    @Bean
    public Bootstrap dhtServerBootstrap() {
        group = group();
        Bootstrap b = new Bootstrap();
        b.group(group).channel(NioDatagramChannel.class).handler(channelInitializer);
        Map<ChannelOption<?>, Object> udpChannelOptions = udpChannelOptions();
        Set<ChannelOption<?>> keySet = udpChannelOptions.keySet();
        for (ChannelOption option : keySet) {
            b.option(option, udpChannelOptions.get(option));
        }
        return b;
    }

    @Bean
    public EventLoopGroup group() {
        return new NioEventLoopGroup();
    }

    @Bean
    public InetSocketAddress udpSocketAddress() {
        return new InetSocketAddress(udpPort);
    }

    @Bean
    public Map<ChannelOption<?>, Object> udpChannelOptions() {
        Map<ChannelOption<?>, Object> options = new HashMap<ChannelOption<?>, Object>();
        options.put(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
        options.put(ChannelOption.SO_BROADCAST, true);
        options.put(ChannelOption.SO_RCVBUF, rcvbuf);
        options.put(ChannelOption.SO_SNDBUF, sndbuf);
        return options;
    }

    /**
     * 优雅关闭
     *
     * @param contextClosedEvent
     */
    @Override
    public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
        if (contextClosedEvent.getApplicationContext().getParent() == null) {
            group.shutdownGracefully();
        }
    }
}
